In [1]:
from plotly import graph_objs as go
import plotly
import numpy as np
import math
pi = math.pi

This is equation that describes string vibrations: $$\frac{\partial^2 U}{\partial t^2}= \frac{\partial^2 U}{\partial x^2}$$

This is the d'Alembert formula for string vibrations: $$U(x,t) = \frac{\varphi(x + at) + \varphi(x- at)}{2} + \frac{1}{2a} \int\limits_{x-at}^{x+at}\psi(\alpha)d\alpha$$ So, lets find $\varphi$:

We have initial conditions:} $\varphi=\begin{cases}\arccos\sin\pi x,&|x|\leqslant 1,\\ 0,&|x|>1;\end{cases}\quad$

In [2]:
def fi(x: int) -> int:
    result = 0
    if abs(x)<=1:
        result = math.acos(math.sin(pi*x))
    else:
        result = 0
    return result

Lets find $ \psi$

We have initial conditions: $\psi=\begin{cases}\cos\pi x,&|x|\leqslant 1,\\ 0,&|x|>1;\end{cases}$

So solve the integral: $\int\limits_{x-at}^{x+at}\psi(\alpha)d\alpha = \int\cos(\pi x)dx = \frac{sin(\pi x)}{\pi} $

In [3]:
def Psy(x: int) -> int:
    result = 0 
    if -1<x<=1:
        result = (math.sin(pi*x))/(pi)
    if x>1:
        result = Psy(1)    
    return result

Substitute in the part of the formula:

In [4]:
def calculation_psy(x: int,a : int,t: int) -> int:
    return Psy(x+a*t)-Psy(x-a*t)

Substitute in the d'Alembert formula:

In [5]:
def U(xArr,t,a) -> list:
    res = []
    for x in xArr:
        res.append((fi(x+a*t)+fi(x-a*t))/2+calculation_psy(x,a,t)/(2*a))
    return res

I chose a segment [-20:20], a = 1 from condition

In [6]:
a=1
begin_of_x = -20
end_of_x = 20
step_x = 0.1

pull_of_x = np.arange(begin_of_x,end_of_x,step_x)
In [7]:
stack = []
step_t =0.1
T = 10
delta_t = 0.1
for t in np.arange(0,T,delta_t):
    stack.append(go.Frame(data=go.Scatter(x=pull_of_x, y=U(pull_of_x,t,a))))
In [8]:
go.Figure(data=go.Scatter(x=pull_of_x, y=U(pull_of_x,0,a)),layout=go.Layout(
        xaxis=dict(range=[begin_of_x,end_of_x], autorange=False),
        yaxis=dict(range=[-5, 5], autorange=False),
        title="Infinite Oscillating String",
        updatemenus=[dict(
            type="buttons",
            buttons=[dict(label="Play",
                          method="animate",
                          args=[None])])]
    ),frames=stack)
In [ ]: